package gui.inventory;

import facades.ItemFacade;
import facades.Notification;
import facades.NotificationEnum;
import facades.ProductFacade;
import facades.StorageFacade;
import gui.common.*;
import gui.item.*;
import gui.product.*;
import hitExceptions.InvalidOperationException;


import java.util.Iterator;
import java.util.Observer;
import java.util.Observable;

import java.util.*;

import coreModel.HIT;

import coreModel.ItemManager;
import coreModel.ProductContainer;
import coreModel.ProductGroup;
import coreModel.ProductManager;
import coreModel.Unit;

import coreModel.Item;
import coreModel.Product;


import coreModel.StorageUnit;
import coreModel.StorageUnitManager;

/**
 * Controller class for inventory view.
 */
public class InventoryController extends Controller 
implements IInventoryController, Observer {

	private ProductContainerData root;
	//	private ProductContainerData prodContainerDataSelected;
	//	private ProductData productDataSelected;
	//	private ItemData itemDataSelected;

	/**
	 * Constructor.
	 *  
	 * @param view Reference to the inventory view
	 */
	public InventoryController(IInventoryView view) {
		super(view);
		try
		{
			//load previous data into model
			HIT.getInstance().load();
		}
		catch(Exception e)
		{
			//ignore
			getView().displayErrorMessage("Couldn't Load Serialized File");
			e.printStackTrace();
		}
		StorageFacade.getInstance().addObserver(this);
		ProductFacade.getInstance().addObserver(this);
		ItemFacade.getInstance().addObserver(this);

		root = new ProductContainerData();

		construct();
	}

	/**
	 * Returns a reference to the view for this controller.
	 */
	@Override
	protected IInventoryView getView() {
		return (IInventoryView)super.getView();
	}

	/**
	 * Loads data into the controller's view.
	 * 
	 *  {@pre None}
	 *  
	 *  {@post The controller has loaded data into its view}
	 */
	@Override
	protected void loadValues() 
	{	

		root = new ProductContainerData();

		StorageUnitManager SUMgr = HIT.getInstance().getStorageUnitManager();

		Collection<StorageUnit> SUnits = SUMgr.getStorageUnits();
		Collections.sort( (List<StorageUnit>) SUnits );

		Iterator<StorageUnit> itr = SUnits.iterator();

		while ( itr.hasNext() )
		{
			StorageUnit tmpSU = (StorageUnit) itr.next();
			ProductContainerData tmpPCD = new ProductContainerData(tmpSU.getName());
			tmpPCD.setTag(tmpSU);

			tmpPCD = recurseChildren(tmpSU);


			root.addChild(tmpPCD);
		} 

		getView().setProductContainers(root);
	}

	private ProductContainerData recurseChildren(ProductContainer pc)
	{
		ProductContainerData pcData = new ProductContainerData(pc.getName());
		pcData.setTag(pc);

		Collection<ProductGroup> children = pc.getChildren();
		if ( children == null || children.size() == 0 )
			return pcData;

		Collections.sort( (List<ProductGroup>)children );

		Iterator<ProductGroup> itr = children.iterator();

		ProductContainerData tmpPG;
		while(itr.hasNext())
		{
			tmpPG = recurseChildren( (ProductGroup)itr.next() );
			pcData.addChild(tmpPG);
		}

		return pcData;
	}

	/**
	 * Sets the enable/disable state of all components in the controller's view.
	 * A component should be enabled only if the user is currently
	 * allowed to interact with that component.
	 * 
	 * {@pre None}
	 * 
	 * {@post The enable/disable state of all components in the controller's view
	 * have been set appropriately.}
	 */
	@Override
	protected void enableComponents() 
	{

		return;
	}

	//
	// IInventoryController overrides
	//

	/**
	 * Returns true if and only if the "Add Storage Unit" menu item should be enabled.
	 */
	@Override
	public boolean canAddStorageUnit() 
	{
		return true;
	}

	/**
	 * Returns true if and only if the "Add Items" menu item should be enabled.
	 */
	@Override
	public boolean canAddItems() 
	{
		return true;
	}

	/**
	 * Returns true if and only if the "Transfer Items" menu item should be enabled.
	 */
	@Override
	public boolean canTransferItems() {
		return true;
	}

	/**
	 * Returns true if and only if the "Remove Items" menu item should be enabled.
	 */
	@Override
	public boolean canRemoveItems() {
		return true;
	}

	/**
	 * Returns true if and only if the "Delete Storage Unit" menu item should be enabled.
	 */
	@Override
	public boolean canDeleteStorageUnit() 
	{
		if(HIT.getInstance().getStorageUnitManager().canRemoveStorageUnit((StorageUnit)getView()
				.getSelectedProductContainer().getTag()))
		{
			return true;
		}
		return false;
	}

	/**
	 * This method is called when the user selects the "Delete Storage Unit" menu item.
	 */
	@Override
	public void deleteStorageUnit() 
	{
		StorageFacade.getInstance().deleteStorageUnit((StorageUnit)getView().
				getSelectedProductContainer().getTag());
	}

	/**
	 * Returns true if and only if the "Edit Storage Unit" menu item should be enabled.
	 */
	@Override
	public boolean canEditStorageUnit() 
	{
		return true;
	}

	/**
	 * Returns true if and only if the "Add Product Group" menu item should be enabled.
	 */
	@Override
	public boolean canAddProductGroup() 
	{
		return true;
	}

	/**
	 * Returns true if and only if the "Delete Product Group" menu item should be enabled.
	 */
	@Override
	public boolean canDeleteProductGroup() 
	{
		return ((ProductContainer) getView().
				getSelectedProductContainer().getTag()).canRemoveContainer();
	}

	/**
	 * Returns true if and only if the "Edit Product Group" menu item should be enabled.
	 */
	@Override
	public boolean canEditProductGroup() 
	{
		return true;
	}

	/**
	 * This method is called when the user selects the "Delete Product Group" menu item.
	 */
	@Override
	public void deleteProductGroup() 
	{
		StorageFacade.getInstance().deleteProductGroup(
				(ProductGroup) getView().getSelectedProductContainer().getTag());
	}

	private Random rand = new Random();

	private String getRandomBarcode() {
		Random rand = new Random();
		StringBuilder barcode = new StringBuilder();
		for (int i = 0; i < 12; ++i) {
			barcode.append(((Integer)rand.nextInt(10)).toString());
		}
		return barcode.toString();
	}

	/**
	 * This method is called when the selected item container changes.
	 */
	@Override
	public void productContainerSelectionChanged() 
	{
		//added to keep track of state after an add
		GUISelections.getInstance().setContainer( getView().getSelectedProductContainer() );

		//for context pane******************************************
		if(getView().getSelectedProductContainer()==null)
		{
			getView().setContextGroup("");
			getView().setContextSupply("");
			getView().setContextUnit("");
		}
		else if(getView().getSelectedProductContainer()==root)
		{
			getView().setContextGroup("");
			getView().setContextSupply("");
			getView().setContextUnit("ALL");
		}
		else if((ProductContainer)getView().getSelectedProductContainer().getTag()
				instanceof ProductGroup)
		{
			ProductGroup tmp = (ProductGroup) getView().getSelectedProductContainer().getTag();
			getView().setContextGroup(tmp.getName());
			getView().setContextUnit(tmp.getParent().getName());
			//for correctly displaying the supply
			if(tmp.getThreeMonths().getSupplySize()==0)
			{
				getView().setContextSupply("");
			}
			else if(tmp.getThreeMonths().getSupplyUnit()==Unit.COUNT)
			{
				String display=""+(int)tmp.getThreeMonths().getSupplySize();
				display+=" "+tmp.getThreeMonths().getSupplyUnit();
				getView().setContextSupply(display);

			}
			else
			{
				getView().setContextSupply(tmp.getThreeMonths().toString());
			}

		}
		else
		{
			getView().setContextGroup("");
			getView().setContextSupply("");
			getView().setContextUnit(getView().getSelectedProductContainer().getName());
		}


		ProductContainerData selectedPCD = this.getView().getSelectedProductContainer();

		if (selectedPCD == null)
		{
			this.getView().setProducts( new ProductData[0]);
			this.getView().setItems( new ItemData[0]);
			return;
		}
		//end of code for context pane******************************************

		//		ProductContainer selectedPC = (ProductContainer)selectedPCD.getTag();
		Collection <ProductData> products = new ArrayList<ProductData>();

		if (selectedPCD == root)
		{
			products = getProductsFromRoot();
		}
		else
		{
			products = getProductsFromContainer(selectedPCD);
		}

		Collections.sort( (List<ProductData>)products );

		this.getView().setProducts( products.toArray(new ProductData[0]) );
		this.getView().setItems( new ItemData[0]);
	}	


	//		ProductManager pMgr = HIT.getInstance().getProductManager();
	//
	//		Collection <Product> tmpL = pMgr.getProductsOfContainer(selectedPC);
	//
	//		if (tmpL == null || tmpL.isEmpty())
	//		{
	//			this.getView().setProducts( new ProductData[0]);
	//			return;
	//		}
	//
	//		Collection <Product> pList = new ArrayList<Product>(tmpL);
	//		Collections.sort( (List<Product>)pList );
	//
	//
	//		Collection<ProductData> pdList = new ArrayList();
	//		Iterator itr = pList.iterator();
	//		while(itr.hasNext())
	//		{
	//			ProductData tmpPD = DataConverter.ConvertProduct( (Product)itr.next(), selectedPC);
	//			pdList.add(tmpPD);
	//		}
	//
	//		this.getView().setProducts( pdList.toArray(new ProductData[0]) );
	//		this.getView().setItems( new ItemData[0]);


	private Collection<ProductData> getProductsFromRoot()
	{
		ProductManager pMgr = HIT.getInstance().getProductManager();

		Collection <Product> allProducts = pMgr.getAllProducts();

		Collection <ProductData> allProductData = new ArrayList<ProductData>();


		Iterator<Product> itr = allProducts.iterator();
		while ( itr.hasNext() )
		{
			// Convert and add to list of PData
			ProductData tmpPD = DataConverter.ConvertProduct(itr.next(), null);

			allProductData.add(tmpPD);
		}

		return allProductData;
	}


	private Collection<ProductData> getProductsFromContainer(ProductContainerData pcd)
	{
		Collection <ProductData> pdList = new ArrayList<ProductData>();

		ProductManager pMgr = HIT.getInstance().getProductManager();


		// get ProductContainer
		ProductContainer pc = (ProductContainer)pcd.getTag();

		// get Products from PC
		Collection <Product> pList = pMgr.getProductsOfContainer(pc);

		if (pList == null)
			return pdList;

		// loop through Products, convert, add to pdList
		Iterator<Product> itr = pList.iterator();
		while ( itr.hasNext() )
		{
			Product product = itr.next();
			ProductData tmpPD = DataConverter.ConvertProduct(product, pc);

			pdList.add(tmpPD);
		}

		// return PData list

		return pdList;
	}

	/**
	 * This method is called when the selected product changes.
	 */
	@Override
	public void productSelectionChanged()
	{


		ProductContainerData selectedPCD = this.getView().getSelectedProductContainer();
		if (selectedPCD == null)
		{
			this.getView().setProducts( new ProductData[0]);
			this.getView().setItems( new ItemData[0]);
			return;
		}

		ProductData selectedPD = this.getView().getSelectedProduct();
		GUISelections.getInstance().setProduct( selectedPD );
		if (selectedPD == null)
		{
			this.getView().setItems( new ItemData[0]);
			return;
		}

		Product selectedP = (Product)selectedPD.getTag();
		ProductContainer selectedPC = (ProductContainer)selectedPCD.getTag();

		Collection<ItemData> items = new ArrayList<ItemData>();

		if (selectedPCD == root)
			selectedPC = null;

		items = getItemsFromContainerByProduct(selectedPC, selectedP);

		Collections.sort( (List<ItemData>)items );

		this.getView().setItems( items.toArray( new ItemData[0]) );		

	}

	private Collection<ItemData> getItemsFromContainerByProduct
	(ProductContainer selPC, Product selP)
	{
		Collection<ItemData> idList = new ArrayList<ItemData>();

		ItemManager iMgr = HIT.getInstance().getItemManager();



		Collection<Item> iList;
		String sUnit;
		if (selPC == null) // we're on the root
		{
			iList = iMgr.getAllItemsOfProduct(selP);
			sUnit= "Storage Units"; // add for the case where it is the root unit
		}
		else
		{
			iList = iMgr.getItemsByContainerAndProduct(selPC, selP);

			// move this to only check when it isn't the root
			sUnit = findStorageUnit(selPC).getName(); 
		}

		if (iList == null)
			return idList;



		Iterator<Item> itr = iList.iterator();
		while (itr.hasNext())
		{
			ItemData tmpID = new ItemData(itr.next());
			//tmpID.setStorageUnit(sUnit);
			idList.add( tmpID );
		}

		return idList;
	}

	private ProductContainer findStorageUnit(ProductContainer selPC)
	{
		ProductContainer tmpPC = selPC;

		while(!(tmpPC instanceof StorageUnit))
		{
			ProductGroup tmpPG = (ProductGroup)tmpPC;
			tmpPC = tmpPG.getParent();
		}

		return tmpPC;
	}


	/**
	 * This method is called when the selected item changes.
	 */
	@Override
	public void itemSelectionChanged() 
	{
		GUISelections.getInstance().setItem( getView().getSelectedItem() );
		return;
	}

	/**
	 * Returns true if and only if the "Delete Product" menu item should be enabled.
	 */
	@Override
	public boolean canDeleteProduct()
	{
		if(getView().getSelectedProduct()==null)
			return false;
		Product prd = ((Product)getView().getSelectedProduct().getTag());
		if(getView().getSelectedProductContainer()==root)
		{
			return HIT.getInstance().getItemManager().canRemoveProductFromAll(prd);
		}
		else
		{

			ProductContainer container = (ProductContainer) getView().
			getSelectedProductContainer().getTag();
			return HIT.getInstance().getProductManager().
			canRemoveProductFromContainer(prd, container);

		}
	}

	/**
	 * This method is called when the user selects the "Delete Product" menu item.
	 */
	@Override
	public void deleteProduct() 
	{


		Product product = (Product)getView().getSelectedProduct().getTag();
		ProductContainer parent = (ProductContainer)this.getView().
		getSelectedProductContainer().getTag();

		try
		{
			if (root == this.getView().getSelectedProductContainer() )
			{
				ProductFacade.getInstance().removeProductFromSystem(product);
			}
			else
				ProductFacade.getInstance().removeProductFromContainer(product, parent );
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	/**
	 * Returns true if and only if the "Edit Item" menu item should be enabled.
	 */
	@Override
	public boolean canEditItem() 
	{
		if(getView().getSelectedItem()==null)
			return false;
		return true;
	}

	/**
	 * This method is called when the user selects the "Edit Item" menu item.
	 */
	@Override
	public void editItem()
	{
		getView().displayEditItemView();
	}

	/**
	 * Returns true if and only if the "Remove Item" menu item should be enabled.
	 */
	@Override
	public boolean canRemoveItem() 
	{
		if(getView().getSelectedItem()!=null)
			return true;
		return false;
	}

	/**
	 * This method is called when the user selects the "Remove Item" menu item.
	 */
	@Override
	public void removeItem()
	{
		GUISelections.getInstance().setItem(getView().getSelectedItem());
		GUISelections.getInstance().setProduct(getView().getSelectedProduct());

		Item item = (Item) getView().getSelectedItem().getTag();
		ItemFacade.getInstance().removeItem(item);


	}

	/**
	 * Returns true if and only if the "Edit Product" menu item should be enabled.
	 */
	@Override
	public boolean canEditProduct()
	{
		if(getView().getSelectedProduct()==null)
			return false;
		return true;
	}

	/**
	 * This method is called when the user selects the "Add Product Group" menu item.
	 */
	@Override
	public void addProductGroup()
	{
		getView().displayAddProductGroupView();
		//added to keep track of state
		trackState();
	}

	/**
	 * This method is called when the user selects the "Add Items" menu item.
	 */
	@Override
	public void addItems() 
	{
		getView().displayAddItemBatchView();
		//added to keep track of state
		//trackState();
	}

	/**
	 * This method is called when the user selects the "Transfer Items" menu item.
	 */
	@Override
	public void transferItems() 
	{
		GUISelections.getInstance().setContainer(getView().getSelectedProductContainer());
		GUISelections.getInstance().setItem(getView().getSelectedItem());
		GUISelections.getInstance().setProduct(getView().getSelectedProduct());
	
		getView().displayTransferItemBatchView();
		//added to keep track of state
		//trackState();
	}

	/**
	 * This method is called when the user selects the "Remove Items" menu item.
	 */
	@Override
	public void removeItems()
	{
		
		GUISelections.getInstance().setItem(getView().getSelectedItem());
		GUISelections.getInstance().setProduct(getView().getSelectedProduct());
		
		getView().displayRemoveItemBatchView();
		//added to keep track of state

	}

	/**
	 * This method is called when the user selects the "Add Storage Unit" menu item.
	 */
	@Override
	public void addStorageUnit() 
	{
		getView().displayAddStorageUnitView();
	}

	private void trackState()
	{
		//added to keep track of state
		getView().selectItem( GUISelections.getInstance().getItem() );
		getView().selectProduct( GUISelections.getInstance().getProduct() );
		ProductData selectedPD = this.getView().getSelectedProduct();

		getView().selectProductContainer( GUISelections.getInstance().getContainer() );
		selectedPD = this.getView().getSelectedProduct();
		productContainerSelectionChanged();
		selectedPD = this.getView().getSelectedProduct();
		productSelectionChanged();
		itemSelectionChanged();
	}

	/**
	 * This method is called when the user selects the "Edit Product Group" menu item.
	 */
	@Override
	public void editProductGroup()
	{

		getView().displayEditProductGroupView();
		trackState();
	}

	/**
	 * This method is called when the user selects the "Edit Storage Unit" menu item.
	 */
	@Override
	public void editStorageUnit() 
	{
		getView().displayEditStorageUnitView();
		trackState();
	}

	/**
	 * This method is called when the user selects the "Edit Product" menu item.
	 */
	@Override
	public void editProduct()
	{
		getView().displayEditProductView();
	}

	/**
	 * This method is called when the user drags a product into a
	 * product container.
	 * 
	 * @param productData Product dragged into the target product container
	 * @param containerData Target product container
	 */
	@Override
	public void addProductToContainer(ProductData productData, ProductContainerData containerData) 
	{	
		/*	BRAINSTORM

		 	destSU = SU of destPC

		 	if product !exist at destSU
		 		add it to destSU w/ no items

		 	if product exists at destSU
		 		remove product from its parent
		 		add product w/items to destPC

		 */

		Product product = (Product) productData.getTag();

		ProductContainer destPC = (ProductContainer)containerData.getTag();
		ProductContainer destSU = findStorageUnit(destPC);

		ProductManager pMgr = HIT.getInstance().getProductManager();
		ProductContainer srcPC = pMgr.locationOfProductInContainer(product, destSU);

		if ( srcPC == null ) 
		{
			ProductFacade.getInstance().addProduct(product, destPC);
			return;
		}

		// the product exists in the destSU

		try
		{
			ProductFacade.getInstance().moveProduct(product, srcPC, destPC);
		} 
		catch (InvalidOperationException e)
		{	}

	}

	/**
	 * This method is called when the user drags an item into
	 * a product container.
	 * 
	 * @param itemData Item dragged into the target product container
	 * @param containerData Target product container
	 */
	@Override
	public void moveItemToContainer(ItemData itemData, ProductContainerData containerData) 
	{

		//if adding an item to the same su
		ProductContainer parentUnit=((Item)itemData.getTag()).getParentContainer();
		ProductContainer destinationUnit=(ProductContainer) containerData.getTag();
		Item theItem=(Item) itemData.getTag();

		//move inside the same container
		if(inSameStorageUnit(parentUnit,destinationUnit))
		{
			System.out.println("same unit");
			try
			{
				ProductFacade.getInstance().moveProduct(theItem.getProduct(), 
						parentUnit,destinationUnit);
			} 
			catch (InvalidOperationException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		else
		{
			// this may not work depends on what ammon does
			try
			{
				ProductContainer parent = HIT.getInstance().getStorageUnitManager().
				getParentStorageUnit(destinationUnit);
				//product is not in destination more normally
				ProductContainer newDestination =HIT.getInstance().getProductManager().
				locationOfProductInContainer(theItem.getProduct(), parent);
				if(newDestination==null)
				{
					HIT.getInstance().getItemManager().addContainer(destinationUnit);
					ItemFacade.getInstance().transferItem((Item)itemData.getTag(),
							(ProductContainer)containerData.getTag());
				}
				else
				{
					HIT.getInstance().getProductManager().moveProduct(
							theItem.getProduct(),newDestination, destinationUnit);
					HIT.getInstance().getItemManager().addContainer(destinationUnit);
					ItemFacade.getInstance().transferItem((Item)itemData.getTag(),
							destinationUnit);
				}

			} 
			catch (InvalidOperationException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		//trackState();
	}


	private boolean inSameStorageUnit(ProductContainer parentUnit,
			ProductContainer destinationUnit)
	{
		ProductContainer answer1 = HIT.getInstance().getStorageUnitManager().
		getParentStorageUnit(parentUnit);
		ProductContainer answer2 = HIT.getInstance().getStorageUnitManager().
		getParentStorageUnit(destinationUnit);

		if(answer1==answer2)
			return true;
		return false;
	}



	public void update(Observable obs, Object obj)
	{		

		if (obs instanceof StorageFacade)
		{
			Notification notification = (Notification) obj;
			//if something was done to a SU
			if( notification.getNotification()==NotificationEnum.STORAGE_UNIT)
				storageUnitUpdate(notification);

			//if something was done to a PG
			if(notification.getNotification()==NotificationEnum.PRODUCT_GROUP)
				productGroupUpdate(notification);

			trackState();
		}
		else if ( obs instanceof ProductFacade )
		{
			Notification notification = (Notification) obj;

			updateproduct(notification);
		}
		else if ( obs instanceof ItemFacade )
		{
			Notification notification = (Notification) obj;
			updateItem(notification);
		}
		else
		{
			construct();
			System.out.println("Inventory controller: Didn't recognize who updated it!");
		}
	}


	private void updateItem(Notification notification)
	{

		itemSelectionChanged();
		switch(notification.getAction())
		{
		case EDIT:
			ItemData d = new ItemData();
			d.setTag(notification.getUpdatedItem());
			//added to fix bug 212, now all items of this product are reloaded upon an edit
			productSelectionChanged();

			getView().selectItem(d);
			break;

		case ADD:
			productContainerSelectionChanged();
			getView().selectProduct(GUISelections.getInstance().getProduct());
			productSelectionChanged();
			getView().selectItem(GUISelections.getInstance().getItem());
			break;
		case TRANSFER:
		case REMOVE:
			//update products
			productContainerSelectionChanged();

			//select product
			System.out.println(GUISelections.getInstance().getProduct());
			getView().selectProduct(GUISelections.getInstance().getProduct());
			//update items
			productSelectionChanged();
			//select item
			System.out.println(GUISelections.getInstance().getItem());
			getView().selectItem(GUISelections.getInstance().getItem());
			break;
		default:
		}



	}


	private void updateproduct(Notification notification)
	{
		productContainerSelectionChanged();

		if(notification.getAction()==NotificationEnum.EDIT)
		{

			ProductData p = new ProductData();
			p.setTag(notification.getUpdatedItem());
			getView().selectProduct(p);
			productSelectionChanged();
			if(GUISelections.getInstance().getItem()!=null)
				getView().selectItem(GUISelections.getInstance().getItem());

		}
		else if(notification.getAction()==NotificationEnum.TRANSFER)
		{
			ProductData p = new ProductData();
			p.setTag(notification.getUpdatedItem());
			getView().selectProduct(p);
			productSelectionChanged();
		}
		else if(notification.getAction()==NotificationEnum.ADD)
		{
			//update product selection		
			getView().selectProduct(GUISelections.getInstance().getProduct());
			//populate the update
			productSelectionChanged();
			//update item selection
			//getView().selectItem(GUISelections.getInstance().getItem());
			if(GUISelections.getInstance().getItem()!=null)
			{
				getView().selectItem(GUISelections.getInstance().getItem());

				//				productContainerSelectionChanged();

			}
		}


	}

	/**
	 * Performs the update of productGroups
	 * @param update Notification Object
	 */
	private void productGroupUpdate(Notification update)
	{
		switch (update.getAction())
		{
		case ADD:

			//get the parentContainer info
			ProductContainer parentContainer= ((ProductGroup) 
					update.getUpdatedItem()).getParent();
			//get parent data obj
			ProductContainerData parentContainerData=getParentContainerData(parentContainer);

			//get the list of children
			Collection<ProductGroup> children = parentContainer.getChildren();

			//sort children
			Collections.sort( (List<ProductGroup>)children );
			Iterator<ProductGroup> itr = children.iterator();

			//find where to insert new child
			for(int x=0;itr.hasNext();x++)
			{
				ProductGroup tmpGP= itr.next();
				if (tmpGP.getName().equals(((ProductContainer) 
						update.getUpdatedItem()).getName()))
				{
					ProductContainerData p= new ProductContainerData(tmpGP.getName());
					p.setTag(tmpGP);
					getView().insertProductContainer(parentContainerData, p, x);
					GUISelections.getInstance().setContainer(p);
				}
			}

			break;
		case EDIT:

			//get the parentContainer info
			parentContainer= ((ProductGroup) update.getUpdatedItem()).getParent();
			//get parent data obj
			parentContainerData=getParentContainerData(parentContainer);

			//get the list of children
			children = parentContainer.getChildren();

			//sort children
			Collections.sort( (List<ProductGroup>)children );
			itr = children.iterator();

			//find where to insert new child
			for(int x=0;itr.hasNext();x++)
			{
				ProductGroup tmpPG= itr.next();
				if (tmpPG.getName().equals(((ProductContainer) update.getUpdatedItem()).getName()))
				{
					ProductContainerData selectedContainer = GUISelections.
					getInstance().getContainer();
					//edit the name
					getView().renameProductContainer(selectedContainer,tmpPG.getName(), x);
				}
			}
			break;
		case REMOVE:
			getView().deleteProductContainer(GUISelections.getInstance().getContainer());
			//none selected
			GUISelections.getInstance().setContainer(null);
			break;
		default:
			System.err.println("Should never get to this default switch");
			assert(false);
			break;

		}
	}

	/**
	 * Recurses through the root structure to find the productContainerData that is associated with
	 * the parentContainer passed in
	 * @param parentContainer 
	 * @return null if not found else the productContainerData obj
	 */
	private ProductContainerData getParentContainerData(
			ProductContainer parentContainer)
	{
		Stack<ProductContainerData> stack = new Stack<ProductContainerData>();
		stack.push(root);

		while(!stack.isEmpty())
		{
			ProductContainerData tmpContainer =stack.pop();
			//set the tag in a new data obj so that the .equals will work
			ProductContainerData ralph =new ProductContainerData();
			ralph.setTag(parentContainer);

			if(tmpContainer.equals(ralph))
				return tmpContainer;

			for(int x=0;x<tmpContainer.getChildCount();x++)
			{
				stack.push(tmpContainer.getChild(x));
			}
		}
		return null;
	}

	/**
	 * performs the update of the StorageUnits for the GUI
	 * @param update Notification Object
	 */
	private void storageUnitUpdate(Notification update)
	{
		StorageUnitManager SUMgr = HIT.getInstance().getStorageUnitManager();
		switch (update.getAction())
		{
		case ADD:
			//populate and sort the SU list
			Collection<StorageUnit> SUnits = SUMgr.getStorageUnits();
			Collections.sort( (List<StorageUnit>) SUnits );
			Iterator<StorageUnit> itr = SUnits.iterator();

			//find where to insert the new SU
			for(int x=0; itr.hasNext();x++)
			{
				StorageUnit tmpSU = (StorageUnit) itr.next();

				//location found
				if(tmpSU.getName().equals(((ProductContainer) update.getUpdatedItem()).getName()))
				{
					ProductContainerData tmpPCD = new ProductContainerData(tmpSU.getName());
					tmpPCD.setTag(tmpSU);
					// I don't believe i have to add to the root but maybe
					//root.insertChild(tmpPCD,x);
					getView().insertProductContainer(root, tmpPCD, x);
					GUISelections.getInstance().setContainer(tmpPCD);
					break;
				}
			} 

			break;
		case EDIT:

			SUnits = SUMgr.getStorageUnits();
			Collections.sort( (List<StorageUnit>) SUnits );
			itr = SUnits.iterator();

			for(int x=0; itr.hasNext();x++)
			{
				StorageUnit tmpSU = (StorageUnit) itr.next();

				//location found
				if(tmpSU.getName().equals(((ProductContainer) update.getUpdatedItem()).getName()))
				{
					//get the ProductContainerData to edit
					ProductContainerData selectedContainer = GUISelections.
					getInstance().getContainer();
					//edit the name
					getView().renameProductContainer(selectedContainer,tmpSU.getName(), x);
					break;
				}
			} 
			break;
		case REMOVE:
			getView().deleteProductContainer(GUISelections.getInstance().getContainer());
			//none selected
			GUISelections.getInstance().setContainer(null);
			break;
		default:
			System.err.println("Should never get to this default switch");
			assert(false);
			break;

		}

	}


}

